/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.wink.jcdi.server.internal.extension; import org.apache.wink.common.internal.registry.metadata.ApplicationMetadataCollector; import org.apache.wink.common.internal.registry.metadata.ProviderMetadataCollector; import org.apache.wink.common.internal.registry.metadata.ResourceMetadataCollector; import org.apache.wink.jcdi.server.internal.DefaultBeanManagerResolver; import org.apache.wink.jcdi.server.internal.util.CdiUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.Dependent; import javax.enterprise.context.RequestScoped; import javax.enterprise.event.Observes; import javax.enterprise.inject.spi.*; import javax.inject.Singleton; import javax.ws.rs.core.Application; import javax.ws.rs.ext.Provider; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; public class WinkCdiExtension implements Extension { private static final Logger logger = LoggerFactory.getLogger(WinkCdiExtension.class); //don't use a static list - an extension instance gets created per application private List<Class> beanClassesToCheck = new ArrayList<Class>(); @SuppressWarnings("UnusedDeclaration") public <T> void observeProcessInjectionTarget(@Observes ProcessInjectionTarget<T> pij) { logger.trace("observeProcessInjectionTarget({}) entry", pij); Annotation[] annotations = pij.getAnnotatedType().getAnnotations() .toArray(new Annotation[pij.getAnnotatedType().getAnnotations().size()]); if (isJAXRSBean(pij.getAnnotatedType().getJavaClass())) { logger.trace("Was JAX-RS annotated class so changing the injection target"); pij.setInjectionTarget(new WinkInjectionTarget<T>(pij.getInjectionTarget())); } logger.trace("observeProcessInjectionTarget() exit"); } @SuppressWarnings("UnusedDeclaration") public void findJaxRsClasses(@Observes ProcessAnnotatedType<?> processAnnotatedType) { Class<?> beanClass = processAnnotatedType.getAnnotatedType().getJavaClass(); if (ProviderMetadataCollector.isProvider(beanClass) || ApplicationMetadataCollector.isApplication(beanClass) || ResourceMetadataCollector.isResource(beanClass)) { beanClassesToCheck.add(beanClass); } } @SuppressWarnings("UnusedDeclaration") public void validateJaxRsCdiBeans( @Observes AfterDeploymentValidation afterDeploymentValidation, BeanManager beanManager) { DefaultBeanManagerResolver.setBeanManager(beanManager); for (Class beanClass : beanClassesToCheck) { Bean<?> bean = CdiUtils.getBeanFor(beanClass, beanManager); if (bean == null) { continue; //e.g. a vetoed bean } if (ResourceMetadataCollector.isResource(beanClass) && Dependent.class.equals(bean.getScope())) { StringBuilder warning = new StringBuilder("{} gets processed as CDI bean, but uses {} "); if (CdiUtils.isBeanWithScope(beanClass.getAnnotations(), beanManager)) { warning.append("explicitly. "); } else { warning.append("implicitly. "); } warning.append("The suggested scope for this bean is {}. Alternatively use "); warning.append(OptionalScopeAutoUpgradeExtension.class.getName()); Object[] parameters = new Object[]{ beanClass.getName(), Dependent.class.getName(), RequestScoped.class.getName()}; logger.warn(warning.toString(), parameters); continue; } //an extension can change the scope dynamically during bootstrapping -> check it at the end if (!bean.getScope().equals(Singleton.class) && !beanManager.isNormalScope(bean.getScope())) { StringBuilder warning = new StringBuilder(); if (ApplicationMetadataCollector.isApplication(beanClass)) { warning.append("Implementations of ").append(Application.class.getName()); } else { warning.append(Provider.class.getName()).append(" beans"); } warning.append(" are only compatible with singletons. Please add "); warning.append(OptionalScopeAutoUpgradeExtension.class.getName()); warning.append(" Or use "); warning.append(ApplicationScoped.class.getName()); warning.append(" or "); warning.append(Singleton.class.getName()); warning.append(" or a custom scope which keeps only one instance per class for the whole application."); logger.warn(warning.toString()); } } beanClassesToCheck.clear(); } @SuppressWarnings("UnusedDeclaration") public void onShutdown(@Observes BeforeShutdown beforeShutdown) { DefaultBeanManagerResolver.reset(); } private static boolean isJAXRSBean(final Class<?> cls) { if (logger.isTraceEnabled()) { logger.trace("isJAXRSBean({}) entry", cls.getName()); } boolean result = false; if (ProviderMetadataCollector.isProvider(cls)) { result = true; } else if (ResourceMetadataCollector.isResource(cls)) { result = true; } else if (ApplicationMetadataCollector.isApplication(cls)) { result = true; } if (logger.isTraceEnabled()) { logger.trace("isJAXRSBean({}) exit", result); } return result; } }